table of contents
MLOCK(2) | Руководство программиста Linux | MLOCK(2) |
ИМЯ¶
mlock, munlock, mlockall, munlockall - блокирует и разблокирует память
ОБЗОР¶
#include <sys/mman.h> int mlock(const void *addr, size_t len); int munlock(const void *addr, size_t len); int mlockall(int flags); int munlockall(void);
ОПИСАНИЕ¶
Вызовы mlock() и mlockall() блокируют часть или всё виртуальное адресное пространство процесса в ОЗУ, соответственно, предотвращая выгрузку страниц в область подкачки. Вызовы munlock() и munlockall() выполняют обратное действие — разблокируют часть или всё виртуальное адресное пространство процесса, позволяя менеджеру памяти ядра при необходимости выгружать страницы в область подкачки.
mlock() и munlock()¶
Вызов mlock() блокирует страницы в области, начинающейся с адреса addr и длиной len байтов. Все страницы, попадающие, даже частично, в заданную область, будут гарантировано помещены в ОЗУ, если системный вызов выполнился успешно; страницы гарантировано останутся в ОЗУ пока не будут разблокированы.
Вызов munlock() разблокирует страницы в области, начинающейся с адреса addr и длиной len байтов. После этого вызова все страницы, попадающие, даже частично, в заданную область, снова могут быть помещены ядром во внешнее пространство подкачки.
mlockall() и munlockall()¶
Вызов mlockall() блокирует все страницы, отображённые в адресное пространство вызывающего процесса. Сюда входят страницы сегмента кода, данных и стека, а также общих библиотек, страницы с данными пользовательского пространства ядра, общей памяти и файлов, отображённых в память. Все отображённые страницы гарантировано останутся в ОЗУ, если системный вызов выполнился успешно; страницы гарантировано останутся в ОЗУ пока не будут разблокированы.
Аргумент flags создаётся побитовым сложением одной или более следующих констант:
- MCL_CURRENT
- Блокировать все страницы, которые в данный момент отображены в адресное пространство процесса.
- MCL_FUTURE
- Блокировать все страницы, которые будут отображены в адресное пространство процесса в будущем. Это могут быть, например, новые страницы, затребованные для увеличения кучи и стека, а также новые отображённые в память файлы или области общей памяти.
Если указан флаг MCL_FUTURE, то последующий системный вызов (например, mmap(2), sbrk(2), malloc(3)), может завершиться с ошибкой, если бы его работа приводит к превышению разрешённого максимального числа блокируемых байт (см. ниже). Также этот флаг может остановить увеличение стека: ядро будет отказывать в увеличении стека и будет посылать процессу сигнал SIGSEGV.
Вызов munlockall() разблокирует все страницы, отображённые в адресное пространство вызывающего процесса.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
При успешном выполнении системные вызовы возвращают 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение, и в адресном пространстве процесса не выполняется никаких блокировок.
ОШИБКИ¶
- ENOMEM
- (Linux 2.6.9 и новее) У вызывающего процесса установлено ненулевое мягкое ограничение ресурса RLIMIT_MEMLOCK, но он пытается заблокировать больше памяти, чем это разрешено ограничением. Данное ограничение не учитывается у привилегированных процессов (CAP_IPC_LOCK).
- ENOMEM
- (Linux 2.4 и в более ранних) Вызывающий процесс пытается заблокировать более половины ОЗУ.
- EPERM
- Вызывающий не имеет прав (CAP_IPC_LOCK) для выполнения запрошенной операции.
У mlock() и munlock():
- EAGAIN
- Невозможно заблокировать некоторую часть или весь диапазон адресов.
- EINVAL
- Результат добавления start+len стал меньше чем start (например, добавление могло привести к переполнению).
- EINVAL
- (Не в Linux) Значение addr не кратно размеру страницы.
- ENOMEM
- Часть указанного адресного диапазона не соответствует с отображёнными страницами адресного пространства процесса.
У mlockall():
- EINVAL
- Указан неизвестный флаг в flags.
У munlockall():
- EPERM
- (Linux 2.6.8 и более ранних) Вызывающий процесс не имеет достаточно прав (CAP_IPC_LOCK).
СООТВЕТСТВИЕ СТАНДАРТАМ¶
POSIX.1-2001, SVr4.
ДОСТУПНОСТЬ¶
В POSIX-системах, в которых доступны mlock() и munlock(), значение _POSIX_MEMLOCK_RANGE определено в <unistd.h>, а количество байт в странице можно определить из константы PAGESIZE (если определена) в <limits.h> или вызвав sysconf(_SC_PAGESIZE).
В POSIX-системах, в которых доступны mlockall() и munlockall(), значение _POSIX_MEMLOCK, определенное в <unistd.h>, больше нуля (см. также sysconf(3)).
ЗАМЕЧАНИЯ¶
Блокировка памяти используется, в основном, в двух случаях: в алгоритмах реального времени и при работе с секретными данными. Программам реального времени необходима предсказуемость времени выполнения, а страничный обмен (наряду с системой переключения процессов) может привести к неожиданным задержкам в работе. Такие приложения часто переключаются в режим реального времени при помощи вызовы sched_setscheduler(2). Криптографические системы защиты данных очень часто содержат важные данные, например, пароли или секретные ключи, в структурах данных. В результате страничного обмена эти данные могут попасть в область подкачки, находящуюся на устройстве длительного хранения, где к этим данным после того, как они пропадут из ОЗУ, может получить доступ практически кто угодно. (Помните, что в режиме приостановки (suspend) на ноутбуках и некоторых компьютерах на жёсткий диск сохраняется копия памяти ОЗУ системы, независимо от блокировок памяти).
Процессы реального времени, использующие mlockall() для устранения задержек при страничных прерываниях (page fault), должны зарезервировать достаточно заблокированных страниц стека до входа в критический ко времени участок, для того, чтобы вызов функции не мог привести к страничному прерыванию. Это можно выполнить с помощью вызова функции, которая выделит место под достаточно большую автоматическую переменную (массив) и выполнит запись в память для того, чтобы этот массив занял место в странице стека. Таким путём будет отображено достаточно страниц для стека, которые можно заблокировать в ОЗУ. Бесполезная запись нужна для того, чтобы в критическом участке не возникло страничное прерывание для копирования страницы при записи.
Блокировка памяти не наследуется дочерними процессами, созданными при помощи fork(2), и автоматически удаляется (разблокируется) при выполнении execve(2) или при завершении работы процесса.
Блокировка памяти адресного диапазона автоматически удаляется, если этот диапазон становится неотображаемым с помощью вызова munmap(2).
Блокировки памяти не накапливаются, то есть, если страница была заблокирована вызовами mlock() или mlockall() несколько раз, то она будет разблокирована единственным вызовом munlock() для соответствующего диапазона или с помощью вызова munlockall(). Страницы, которые были отображены в несколько мест или несколькими процессами, останутся заблокированными в ОЗУ до тех пор, пока они блокируются хотя бы в одном месте или хотя бы в одном процессе.
Замечания, касающиеся Linux¶
В Linux, mlock() и munlock() автоматически округляют addr в меньшую сторону к размеру границы ближайшей страницы. Однако, в POSIX.1-2001 реализации разрешено требовать, чтобы значение addr было выровнено по размеру страницы, поэтому переносимые приложения должны выполнять выравнивание.
В поле VmLck в имеющемся только в Linux файле /proc/PID/status показано сколько килобайт памяти заблокировал процесс с идентификатором PID с помощью mlock(), mlockall() и mmap(2) с флагом MAP_LOCKED.
Ограничения и права доступа¶
В Linux версии 2.6.8 и более ранних для блокировки памяти процесс должен иметь мандат (CAP_IPC_LOCK), а мягкое ограничение ресурса RLIMIT_MEMLOCK определяет как много памяти можно заблокировать.
Начиная с Linux 2.6.9, привилегированный процесс не имеет ограничения на ограничиваемое количество памяти, а мягкое ограничение ресурса RLIMIT_MEMLOCK определяет предел ограничиваемой памяти для непривилегированных процессов.
ДЕФЕКТЫ¶
В ветви 2.4 ядер Linux до версии 2.4.17 включительно есть дефект, из-за которого флаг MCL_FUTURE у mlockall() наследуется при fork(2). Он устранён в версии 2.4.18.
Начиная с ядра версии 2.6.9, если привилегированный процесс вызывает mlockall(MCL_FUTURE) и, позднее, отказывается от прав (теряет мандат CAP_IPC_LOCK, например, устанавливая свой эффективный UID в ненулевое значение), то последующие выделения памяти (например, с помощью mmap(2), brk(2)) будут завершаться с ошибкой при достижении предела ресурса RLIMIT_MEMLOCK.
СМОТРИТЕ ТАКЖЕ¶
mmap(2), setrlimit(2), shmctl(2), sysconf(3), proc(5), capabilities(7)
2011-09-14 | Linux |